home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / Pascal / Code Resources / Eclectic CDEFs / Gauss CDEF Folder / GaussCDEFStub.p < prev    next >
Text File  |  1997-03-05  |  42KB  |  1,008 lines

  1. {    GaussCDEFStub    }
  2. {}
  3. {    Stub control definition for the GaussCDEF control    }
  4. {}
  5. {    Copyright © Sebastiano Pilla 1996    }
  6. {    <mailto:case@tvol.it>    }
  7.  
  8. {    Control definition procedure for displaying text within a window. Additional variations include:    }
  9. {    1) displaying of the control value to use as a counter    }
  10. {    2) drawing the text pointed to by the refCon field    }
  11. {    3) drawing of the boundary rectangle    }
  12. {    4) drawing always in the active state, ignoring any deactivation    }
  13. {    5) drawing of a 3D-like inset or raised effect    }
  14.  
  15. unit GaussCDEFStub;
  16.  
  17.  
  18. interface
  19.  
  20.  
  21.     uses
  22.         Windows, Palettes, LowMem, Script, TextUtils, CDEFUtils, NeoTextBox;
  23.  
  24.  
  25.     function GaussCDEF (inVarCode: SInt16;
  26.                                     inControlHdl: ControlHandle;
  27.                                     inMessage: ControlDefProcMessage;
  28.                                     inParam: SInt32): SInt32;
  29.  
  30.  
  31. implementation
  32.  
  33.  
  34.     const
  35.         kInGaussControlPart = 60;                            { Value returned for the testCntl message }
  36.  
  37.         kDrawTitleAndValueVarCodeMask = $1;                { Mask for drawing the control title and the control value in the refCon }
  38.         kDrawValueOnlyVarCodeMask = $2;                    { Mask for drawing only the value in the refCon }
  39.         kDrawTextFromRefConVarCodeMask = $4;            { Mask for drawing only the text pointed to by the handle in the refCon }
  40.         kUseWindowFontVarCodeMask = $8;                    { Mask for drawing the text with the owning window font settings }
  41.  
  42.         kDrawBoundingRectangleExtVarCodeMask = $100;        { Mask for drawing the control enclosing rectangle }
  43.         kNeverDimControlExtVarCodeMask = $200;                    { Mask for drawing the control always in the active state }
  44.         kDraw3DEffectExtVarCodeMask = $400;                { Mask for drawing a border (inset or raised) around the bar }
  45.         kUseStdColorsExtVarCodeMask = $800;                { Mask for ignoring the 'cctb' colors }
  46.  
  47.         kDeviceLoopFlags = 0;                                { Flags passed to DeviceLoop }
  48.  
  49.         kMinimumColorDepth = 4;                            { Minimum depth for drawing in color, in bits per pixel }
  50.         kMinimum3DDepth = 8;                            { Minimum depth for drawing the 3D border, in bits per pixel }
  51.  
  52.         kLowOrderByteMask = $00FF;                        { Mask for extracting the low-order byte of a 16-bit integer }
  53.         kHighOrderByteMask = $FF00;                    { Mask for extracting the high-order byte of a 16-bit integer }
  54.  
  55.         kPlainFace = [];
  56.         kBoldFace = [bold];
  57.  
  58.         kEffectThreshold = -100;                            { Checked against contrlMin to determine effect kind }
  59.  
  60.         kDontSwapClipping = false;
  61.  
  62.         kGaussCDEFFormatStr = '#,###,###,###';            { Format string with U.S. separators }
  63.  
  64.         kItl4ResType = 'itl4';
  65.  
  66.         kUSDefaultDecPointSep = '.';                    { Default U.S. decimal point separator }
  67.         kUSDefaultThousandsSep = ',';                    { Default U.S. thousands separator }
  68.  
  69.  
  70.     type
  71.         GaussCDEFDataHandle = ^GaussCDEFDataPtr;
  72.         GaussCDEFDataPtr = ^GaussCDEFData;
  73.         GaussCDEFData = record
  74.                 fDrawControlUPP: DeviceLoopDrawingUPP;    { Pointer to drawing routine }
  75.                 fBlitControlUPP: DeviceLoopDrawingUPP;    { Pointer to blitting routine }
  76.                 fOffscreenWorldPtr: GWorldPtr;                { Pointer to offscreen world }
  77.                 fTextHandle: Handle;                            { Handle to text }
  78.                 fReferenceNumPartsPtr: NumberPartsPtr;    { pointer to reference number parts table }
  79.                 fUserNumPartsPtr: NumberPartsPtr;        { pointer to user number parts table }
  80.                 fBlackPattern: Pattern;                        { Standard black pattern }
  81.                 fWhitePattern: Pattern;                        { Standard white pattern }
  82.                 fDitherPattern: Pattern;                        { 50% black-50% white pattern used for dimming }
  83.                 fControlOwnerForeColor: RGBColor;            { Foreground color of the control's window }
  84.                 fControlOwnerContentColor: RGBColor;        { Content color of the control's window }
  85.                 fBlackColor: RGBColor;                        { ($0000, $0000, $0000) black color }
  86.                 fWhiteColor: RGBColor;                        { ($FFFF, $FFFF, $FFFF) white color }
  87.                 fDimGrayColor: RGBColor;                    { ($7FFF, $7FFF, $7FFF) gray color for dimming }
  88.                 fChiselGrayColor: RGBColor;                    { ($AAAA, $AAAA, $AAAA) chisel color as per develop 15 }
  89.                 fVariationCode: SInt16;                        { Extended variation code }
  90.                 fJustification: SInt16;                        { Justification for the text }
  91.                 fSaveTxFont: SInt16;                        { Text font of control's port }
  92.                 fSaveTxSize: SInt16;                        { Text size of control's port }
  93.                 fSaveTxMode: SInt16;                        { Text transfer mode of control's port }
  94.                 fSaveTxFace: Style;                            { Text face of control's port }
  95.                 fHasGrayishTextOr: Boolean;                { True if we can use the grayishTextOr transfer mode to dim text }
  96.                 fOffscreenDrawAvailable: Boolean;            { True if we can draw in the offscreen world, false otherwise }
  97.             end;
  98.  
  99.  
  100.     type
  101.         EffectKind = (eRaisedEffect, eNoEffect, eInsetEffect);
  102.  
  103.  
  104. {    SetDrawingColors    }
  105. {}
  106. {    Sets the appropriate colors for drawing the control    }
  107. {}
  108. {    Entry:    inControlHdl = handle to control    }
  109. {            inControlDataHdl = handle to private CDEF data    }
  110. {            inTargetDevice = device we're currently using    }
  111. {            inDimFlag = TRUE if the control should be dimmed, false otherwise    }
  112. {            inDrawBoundsFlag = TRUE if the bounding rectangle should be drawn, false otherwise    }
  113. {    Exit:    outFrameColor = color for the frame part (if inDrawBoundsFlag = TRUE)    }
  114. {            outTextColor = color for the control's text    }
  115. {            outBodyColor = color for the control's body    }
  116.     procedure SetDrawingColors (var outFrameColor, outTextColor, outBodyColor: RGBColor;
  117.                                     inControlHdl: ControlHandle;
  118.                                     inControlDataHdl: GaussCDEFDataHandle;
  119.                                     inTargetDevice: GDHandle;
  120.                                     inDimFlag, inDrawBoundsFlag: Boolean);
  121.         var
  122.             winBackColor: RGBColor;
  123.             auxCtlHdl: AuxCtlHandle;
  124.             useStdColorsFlag: Boolean;
  125.     begin
  126.  
  127.     { Check if the application wants to use the standard colors }
  128.         useStdColorsFlag := BAND(inControlDataHdl^^.fVariationCode, kUseStdColorsExtVarCodeMask) <> 0;
  129.  
  130.     { Retrieve the background color of the control's owner, stored by the BeginDraw routine }
  131.         winBackColor := inControlDataHdl^^.fControlOwnerContentColor;
  132.  
  133.     { Fetch the auxiliary control record if the application wants the 'cctb' colors and lock the color table }
  134.         if not useStdColorsFlag then
  135.             begin
  136.                 if GetAuxiliaryControlRecord(inControlHdl, auxCtlHdl) then
  137.                     ;
  138.                 if (auxCtlHdl <> nil) & (auxCtlHdl^^.acCTable <> nil) then
  139.                     HLock(Handle(auxCtlHdl^^.acCTable))
  140.                 else
  141.                     useStdColorsFlag := true;        { Fall back to the other case if the color table cannot be found }
  142.             end;
  143.  
  144.     { Set the frame color }
  145.         if inDrawBoundsFlag then
  146.             begin
  147.  
  148.                 if useStdColorsFlag then
  149.                     outFrameColor := inControlDataHdl^^.fBlackColor
  150.                 else
  151.                     outFrameColor := auxCtlHdl^^.acCTable^^.ctTable[cFrameColor].rgb;
  152.  
  153.                 if inDimFlag then
  154.                     if not GetGray(inTargetDevice, winBackColor, outFrameColor) then
  155.                         outFrameColor := inControlDataHdl^^.fDimGrayColor;
  156.             end;
  157.  
  158.     { Set the text color; note that the grayishTextOr transfer mode is applied later, so isn't necessary to set it here }
  159.         if useStdColorsFlag then
  160.             outTextColor := inControlDataHdl^^.fBlackColor
  161.         else
  162.             outTextColor := auxCtlHdl^^.acCTable^^.ctTable[cTextColor].rgb;
  163.  
  164.         if inDimFlag then
  165.             if not GetGray(inTargetDevice, winBackColor, outTextColor) then
  166.                 outTextColor := inControlDataHdl^^.fDimGrayColor;
  167.  
  168.     { Set the body color; note that the dimming pattern (if inDimFlag = TRUE) is applied later }
  169.         if useStdColorsFlag then
  170.             outBodyColor := winBackColor
  171.         else
  172.             outBodyColor := auxCtlHdl^^.acCTable^^.ctTable[cBodyColor].rgb;
  173.  
  174.     { Unlock the color table if it was previously found and locked }
  175.         if not useStdColorsFlag then
  176.             HUnlock(Handle(auxCtlHdl^^.acCTable));
  177.     end;
  178.  
  179.  
  180. {    DrawControlStructure    }
  181. {}
  182. {    Draws the 3D effect, the control's frame and the control's body    }
  183. {}
  184. {    Entry:    ioControlBounds = control's boundary rectangle    }
  185. {            inFrameColor = color for the control's frame (if inDrawBoundsFlag = TRUE)    }
  186. {            inBodyColor = color for the control's body    }
  187. {            inControlDataHdl = handle to control's private data    }
  188. {            inEffectKind = kind of effect requested (if inDrawEffectFlag = TRUE)    }
  189. {            inDrawEffectFlag = TRUE if we should draw the 3D-like effect    }
  190. {            inDrawBoundsFlag = TRUE if we should draw the control's frame    }
  191. {            inDimFlag = TRUE if we should draw a dimmed control    }
  192. {    Exit:    ioControlBounds = control's boundary rectangle, properly inset to draw the text    }
  193. {    Note: The relative positions of the 3D effect and the frame are changed when the requested effect kind    }
  194. {    changes. However, the Gauss CDEF draws the text always in the same position, regardless of the effect kind    }
  195. {    and the frame position.    }
  196. {    Note: I'm not proud of the way I coded this procedure. Hopefully I will improve it in the following versions    }
  197.     procedure DrawControlStructure (var ioControlBounds: Rect;
  198.                                     inFrameColor, inBodyColor: RGBColor;
  199.                                     inControlDataHdl: GaussCDEFDataHandle;
  200.                                     inEffectKind: EffectKind;
  201.                                     inDrawEffectFlag, inDrawBoundsFlag, inDimFlag: Boolean);
  202.         var
  203.             winBackColor: RGBColor;
  204.     begin
  205.  
  206.     { Get the background color of the control's owner }
  207.         winBackColor := inControlDataHdl^^.fControlOwnerContentColor;
  208.  
  209.     { Set the correct background color }
  210.         RGBBackColor(winBackColor);
  211.  
  212.     { Determine if we'll really draw the effect }
  213.         inDrawEffectFlag := inDrawEffectFlag & EqualRGBColorComponents(winBackColor, kLightGrayRGBComp);
  214.  
  215.         if inDrawEffectFlag then
  216.             begin
  217.  
  218.         { The calling application requested the 3D effect, so proceed with the drawing }
  219.                 case inEffectKind of
  220.  
  221.                     eInsetEffect: 
  222.                         begin
  223.  
  224.                 { The control is inactive, so frame a rectangle with the window's background color to }
  225.                 { maintain visual consistency with the other cases }
  226.                             if inDimFlag then
  227.                                 begin
  228.                                     RGBForeColor(winBackColor);
  229.                                     FrameRect(ioControlBounds);
  230.                                 end
  231.  
  232.                 { The control is active, so draw the inset effect; note that the inset effect is drawn 1 pixel }
  233.                 { outside of the frame }
  234.                             else
  235.                                 begin
  236.                                     RGBForeColor(inControlDataHdl^^.fWhiteColor);
  237.                                     MoveTo(ioControlBounds.left + 1, ioControlBounds.bottom - 1);
  238.                                     LineTo(ioControlBounds.right - 1, ioControlBounds.bottom - 1);
  239.                                     LineTo(ioControlBounds.right - 1, ioControlBounds.top);
  240.                                     RGBForeColor(inControlDataHdl^^.fChiselGrayColor);
  241.                                     MoveTo(ioControlBounds.left, ioControlBounds.bottom - 1);
  242.                                     LineTo(ioControlBounds.left, ioControlBounds.top);
  243.                                     LineTo(ioControlBounds.right - 1, ioControlBounds.top);
  244.                                 end;
  245.  
  246.                 { Draw the frame and the body; note that we don't need to check inDrawBoundsFlag here, because }
  247.                 { this is implied by inDrawEffectFlag = TRUE, and the DrawGaussControl did the check for us }
  248.                             InsetRect(ioControlBounds, 1, 1);
  249.                             RGBForeColor(inFrameColor);
  250.                             FrameRect(ioControlBounds);
  251.                             InsetRect(ioControlBounds, 1, 1);
  252.                             RGBForeColor(inBodyColor);
  253.                             PaintRect(ioControlBounds);
  254.                         end;
  255.  
  256.                     eNoEffect: 
  257.                         begin
  258.  
  259.                 { Draw only the frame and the body; we don't need to check the inDrawBoundsFlag because }
  260.                 { at this point we know that inDrawEffectFlag = TRUE }
  261.                             RGBForeColor(inFrameColor);
  262.                             FrameRect(ioControlBounds);
  263.                             InsetRect(ioControlBounds, 1, 1);
  264.                             RGBForeColor(inBodyColor);
  265.                             PaintRect(ioControlBounds);
  266.                             InsetRect(ioControlBounds, 1, 1);
  267.                         end;
  268.  
  269.                     eRaisedEffect: 
  270.                         begin
  271.  
  272.                 { Draw the frame first, then the effect one pixel inside (if possible); see the above discussion }
  273.                 { about the need to check inDrawBoundsFlag when inDrawEffectFlag = TRUE }
  274.                             RGBForeColor(inFrameColor);
  275.                             FrameRect(ioControlBounds);
  276.                             InsetRect(ioControlBounds, 1, 1);
  277.  
  278.                 { The control is inactive, so frame a rectangle with the window's background color to }
  279.                 { maintain visual consistency with the other cases }
  280.                             if inDimFlag then
  281.                                 begin
  282.                                     RGBForeColor(inBodyColor);
  283.                                     FrameRect(ioControlBounds);
  284.                                 end
  285.  
  286.                 { The control is active, so draw the raised effect }
  287.                             else
  288.                                 begin
  289.                                     RGBForeColor(inControlDataHdl^^.fChiselGrayColor);
  290.                                     MoveTo(ioControlBounds.left + 1, ioControlBounds.bottom - 1);
  291.                                     LineTo(ioControlBounds.right - 1, ioControlBounds.bottom - 1);
  292.                                     LineTo(ioControlBounds.right - 1, ioControlBounds.top);
  293.                                     RGBForeColor(inControlDataHdl^^.fWhiteColor);
  294.                                     MoveTo(ioControlBounds.left, ioControlBounds.bottom - 1);
  295.                                     LineTo(ioControlBounds.left, ioControlBounds.top);
  296.                                     LineTo(ioControlBounds.right - 1, ioControlBounds.top);
  297.                                 end;
  298.  
  299.                 { Draw the body }
  300.                             InsetRect(ioControlBounds, 1, 1);
  301.                             RGBForeColor(inBodyColor);
  302.                             PaintRect(ioControlBounds);
  303.                         end;
  304.                     otherwise
  305.                         ;
  306.                 end;
  307.             end
  308.         else
  309.  
  310.     { No effect was requested, so the drawing is *much* simpler to implement }
  311.             begin
  312.                 if inDrawBoundsFlag then
  313.                     begin
  314.                         RGBForeColor(inFrameColor);
  315.                         FrameRect(ioControlBounds);
  316.                         InsetRect(ioControlBounds, 1, 1);
  317.                     end;
  318.                 RGBForeColor(inBodyColor);
  319.                 PaintRect(ioControlBounds);
  320.                 InsetRect(ioControlBounds, 1, 1);
  321.             end;
  322.     end;
  323.  
  324.  
  325. {    ConvertValueToText    }
  326. {}
  327. {    Obtains a text representation of the given value and adds it to the given text handle    }
  328. {}
  329. {    Entry:    inControlDataHdl = handle to control's private data    }
  330. {            inValue = 32-bit value    }
  331. {            ioTextHdl = handle to text on entry (allocated by the caller)    }
  332. {            ioTextLen = length (in bytes) of ioTextHdl on entry    }
  333. {    Exit:    ioTextHdl = handle to text on entry plus value    }
  334. {            ioTextLen = length (in bytes) of ioTextHdl on exit    }
  335. {    Note: If an error occurs in this routine, or if the number-to-text conversion is wrong, we leave ioTextHdl    }
  336. {    and ioTextLen unchanged.    }
  337. {    Note: For references about the algorithm, see the develop 16 article "International Number Formatting" by    }
  338. {    Norbert Lindenberg. The Gauss CDEF implementation may not work on the 7.0 and 7.0.1 System version }
  339. {    shipped in Netherlands and Czechoslovakia. }
  340.     procedure ConvertValueToText (inControlDataHdl: GaussCDEFDataHandle;
  341.                                     inValue: SInt32;
  342.                                     var ioTextHdl: Handle;
  343.                                     var ioTextLen: UInt32);
  344.         var
  345.             numFormat: NumFormatStringRec;
  346.             userFormatStr, valueStr: Str255;
  347.             positions: TripleInt;
  348.             itlHandle: Handle;
  349.             tableOffset, tableLength, mungResult: SInt32;
  350.             formatResult: FormatResultType;
  351.     begin
  352.  
  353.     { Explanation of the algorithm: }
  354.     { 1) Convert our format string, built with the default U.S. separators, to an internal numeric representation }
  355.     { using a reference parts table }
  356.     { 2) Convert this internal numeric representation into a format string with the localized separators, using the }
  357.     { user's parts table specified in the Numbers control panel }
  358.     { 3) Format the number (the inValue parameter) using the user number parts table }
  359.  
  360.     { Extract the user number parts table }
  361.         itlHandle := nil;
  362.         GetIntlResourceTable(smCurrentScript, smNumberPartsTable, itlHandle, tableOffset, tableLength);
  363.         if itlHandle = nil then
  364.             Exit(ConvertValueToText);
  365.         BlockMoveData(Ptr(Ord4(itlHandle^) + tableOffset), inControlDataHdl^^.fUserNumPartsPtr, tableLength);
  366.  
  367.     { Extract the reference parts table from the U.S. 'itl4' resource, supposed to be always present }
  368.         itlHandle := GetResource(kItl4ResType, verUS);
  369.         if itlHandle = nil then
  370.             Exit(ConvertValueToText);
  371.         BlockMoveData(Ptr(Ord4(itlHandle^) + NItl4Handle(itlHandle)^^.defPartsOffset), inControlDataHdl^^.fReferenceNumPartsPtr, NItl4Handle(itlHandle)^^.defPartsLength);
  372.  
  373.     { Undo any change the user may have made to our reference parts table }
  374.         inControlDataHdl^^.fReferenceNumPartsPtr^.data[tokDecPoint].a[1] := kUSDefaultDecPointSep;
  375.         inControlDataHdl^^.fReferenceNumPartsPtr^.data[tokThousands].a[1] := kUSDefaultThousandsSep;
  376.  
  377.     { Convert our format string to an internal representation using the reference number parts table }
  378.         formatResult := FormatResultType(StringToFormatRec(kGaussCDEFFormatStr, inControlDataHdl^^.fReferenceNumPartsPtr^, numFormat));
  379.  
  380.     { Convert the just obtained internal representation to a format string using the user parts table }
  381.         if (formatResult = fFormatOK) or (formatResult = fBestGuess) then
  382.             formatResult := FormatResultType(FormatRecToString(numFormat, inControlDataHdl^^.fUserNumPartsPtr^, userFormatStr, positions));
  383.  
  384.     { Convert this last format string to another internal representation }
  385.         if (formatResult = fFormatOK) or (formatResult = fBestGuess) then
  386.             formatResult := FormatResultType(StringToFormatRec(userFormatStr, inControlDataHdl^^.fUserNumPartsPtr^, numFormat));
  387.  
  388.     { Finally, format the given number into a string, using our internal representation }
  389.         if (formatResult = fFormatOK) or (formatResult = fBestGuess) then
  390.             formatResult := FormatResultType(ExtendedToString(inValue, numFormat, inControlDataHdl^^.fUserNumPartsPtr^, valueStr));
  391.  
  392.     { Now we have a string that we can append to the given text using Munger }
  393.         if ((formatResult = fFormatOK) or (formatResult = fBestGuess)) & (Length(valueStr) > 0) then
  394.             begin
  395.                 mungResult := Munger(ioTextHdl, ioTextLen, nil, 0, @valueStr[1], Length(valueStr));
  396.                 if mungResult >= 0 then
  397.                     ioTextLen := mungResult;
  398.             end;
  399.     end;
  400.  
  401.  
  402. {    DrawGaussControl    }
  403. {}
  404. {    DeviceLoop draw routine to draw the control in either the offscreen world or the control's port    }
  405. {}
  406. {    Entry:    inDepth = depth of current device    }
  407. {            inDeviceFlags = flags describing current device properties (unused)    }
  408. {            inTargetDevice = handle to current device    }
  409. {            inUserData = container for the control's handle }
  410.     procedure DrawGaussControl (inDepth: UInt16;
  411.                                     inDeviceFlags: SInt16;
  412.                                     inTargetDevice: GDHandle;
  413.                                     inUserData: SInt32);
  414.         var
  415.             controlBounds: Rect;
  416.             frameColor, textColor, bodyColor: RGBColor;
  417.             controlHdl: ControlHandle;
  418.             controlDataHdl: GaussCDEFDataHandle;
  419.             textLen: UInt32;
  420.             extVarCode, linesDrawn, endY, lhUsed: SInt16;
  421.             err: OSErr;
  422.             effKind: EffectKind;
  423.             dimFlag, drawBoundsFlag, drawEffectFlag: Boolean;
  424.     begin
  425.  
  426.     { Get the control handle and the data handle }
  427.         controlHdl := ControlHandle(inUserData);
  428.         controlDataHdl := GaussCDEFDataHandle(controlHdl^^.contrlData);
  429.  
  430.     { Get the variation code and the control's rect (in local coordinates relative to the control's window) }
  431.         extVarCode := controlDataHdl^^.fVariationCode;
  432.         controlBounds := controlHdl^^.contrlRect;
  433.  
  434.     { Set the drawing port to either the offscreen world, if available, or the control's port }
  435.         if controlDataHdl^^.fOffscreenDrawAvailable then
  436.             SetGWorld(controlDataHdl^^.fOffscreenWorldPtr, nil)
  437.         else
  438.             SetGWorld(CGrafPtr(controlHdl^^.contrlOwner), nil);
  439.  
  440.     { Always normalize the pen before drawing, to avoid unwanted side effects }
  441.         PenNormal;
  442.  
  443.     { Dim the control only if the 'never dim' variation is UNset and if the control is inactive }
  444.         dimFlag := (BAND(extVarCode, kNeverDimControlExtVarCodeMask) = 0) & (controlHdl^^.contrlHilite = kControlInactivePart);
  445.  
  446.     { Set a well-known clipping; again, this helps avoiding surprises }
  447.         ClipRect(controlBounds);
  448.  
  449.     { Erase the control rectangle, to simulate TETextBox behaviour }
  450.         EraseRect(controlBounds);
  451.  
  452.     { Determine if the calling appl. wants the control's bounding rectangle to be drawn }
  453.         drawBoundsFlag := BAND(extVarCode, kDrawBoundingRectangleExtVarCodeMask) <> 0;
  454.  
  455.         if inDepth >= kMinimumColorDepth then
  456.             begin
  457.  
  458.         { The current device is deep enough for drawing our colors, so fetch them either from our data structure }
  459.         { or from the auxiliary control record, if present }
  460.                 SetDrawingColors(frameColor, textColor, bodyColor, controlHdl, controlDataHdl, inTargetDevice, dimFlag, drawBoundsFlag);
  461.  
  462.         { Determine if the calling application wants a 3D-like effect and what kind of effect. Note that drawing the 3D-like }
  463.         { effect without drawing the control's bounding rectangle would not make much sense }
  464.                 if drawBoundsFlag & (inDepth >= kMinimum3DDepth) then
  465.                     drawEffectFlag := BAND(extVarCode, kDraw3DEffectExtVarCodeMask) <> 0
  466.                 else
  467.                     drawEffectFlag := false;
  468.  
  469.         { Check the contrlMin field against the threshold to see which kind of effect has been requested }
  470.                 if drawEffectFlag then
  471.                     begin
  472.                         if controlHdl^^.contrlMin > kEffectThreshold then
  473.                             effKind := eRaisedEffect
  474.                         else if controlHdl^^.contrlMin = kEffectThreshold then
  475.                             effKind := eNoEffect
  476.                         else if controlHdl^^.contrlMin < kEffectThreshold then
  477.                             effKind := eInsetEffect;
  478.                     end
  479.                 else
  480.                     effKind := eNoEffect;    { Pass eNoEffect to draw properly the frame }
  481.  
  482.         { Draw the frame, the 3D effect (if requested) and the body; note that this routine insets controlBounds }
  483.         { by the correct amount of pixels to always draw the text in the correct position, even if the control rectangle }
  484.         { intersects multiple screens with different depths }
  485.                 DrawControlStructure(controlBounds, frameColor, bodyColor, controlDataHdl, effKind, drawEffectFlag, drawBoundsFlag, dimFlag);
  486.  
  487.         { Setup the colors for drawing the text }
  488.                 RGBForeColor(textColor);
  489.                 RGBBackColor(controlDataHdl^^.fControlOwnerContentColor);
  490.             end
  491.         else
  492.             begin
  493.  
  494.         { Black-&-white or 4-colors device: the controlBounds rectangle is framed with a white pattern to maintain }
  495.         { consistency with the other case and to keep the text aligned if the control rectangle intersects multiple screens }
  496.         { with different depths; then the rectangle is inset by 1 pixel in both directions and is framed with the frame pattern }
  497.         { (if requested) }
  498.                 PenPat(controlDataHdl^^.fWhitePattern);
  499.                 FrameRect(controlBounds);
  500.                 InsetRect(controlBounds, 1, 1);
  501.  
  502.                 if drawBoundsFlag then
  503.                     begin
  504.                         if dimFlag then
  505.                             PenPat(controlDataHdl^^.fDitherPattern)
  506.                         else
  507.                             PenPat(controlDataHdl^^.fBlackPattern);
  508.                     end
  509.                 else
  510.                     PenPat(controlDataHdl^^.fWhitePattern);
  511.                 FrameRect(controlBounds);
  512.                 InsetRect(controlBounds, 2, 2);
  513.  
  514.         { Setup the 'colors' for drawing the text }
  515.                 ForeColor(blackColor);
  516.                 BackColor(whiteColor);
  517.             end;
  518.  
  519.     { Inset again by 1 pixel only in the horizontal direction, to provide enough spacing between the frame and the }
  520.     { text }
  521.         InsetRect(controlBounds, 1, 0);
  522.  
  523.     { Clip everything outside the newly inset control's rectangle }
  524.         ClipRect(controlBounds);
  525.  
  526.     { Setup the correct font, size and style for drawing the text }
  527.         if BAND(extVarCode, kUseWindowFontVarCodeMask) = 0 then
  528.             begin
  529.                 TextFont(LMGetSysFontFam);
  530.                 TextSize(LMGetSysFontSize);
  531.                 TextFace(kPlainFace);
  532.             end
  533.         else
  534.             begin
  535.                 TextFont(controlDataHdl^^.fSaveTxFont);
  536.                 TextSize(controlDataHdl^^.fSaveTxSize);
  537.                 TextFace(controlDataHdl^^.fSaveTxFace);
  538.             end;
  539.  
  540.     { Use grayishTextOr to dim if it's available; otherwise, dim with the 'old' method, calling PaintRect with }
  541.     { PenMode(srcBic) later }
  542.         if dimFlag & controlDataHdl^^.fHasGrayishTextOr then
  543.             TextMode(grayishTextOr)
  544.         else
  545.             TextMode(srcOr);
  546.  
  547.         if BAND(extVarCode, kDrawTextFromRefConVarCodeMask) <> 0 then
  548.             begin
  549.  
  550.         { If this varCode is set, then allocating the text and storing its handle in the refCon is the responsibility of }
  551.         { the calling application. We just fetch the control's refCon, hoping to not end up into hyperspace }
  552.                 controlDataHdl^^.fTextHandle := Handle(controlHdl^^.contrlRfCon);
  553.                 textLen := GetHandleSize(controlDataHdl^^.fTextHandle);
  554.             end
  555.         else
  556.             begin
  557.  
  558.         { No text in refCon, so allocating it is our responsibility; check first what the calling application wants from us }
  559.         { We need to draw the title if the kDrawTitleAndValue variation is set or the kDrawValueOnly variation is clear }
  560.                 if (BAND(extVarCode, kDrawTitleAndValueVarCodeMask) <> 0) or (BAND(extVarCode, kDrawValueOnlyVarCodeMask) = 0) then
  561.                     begin
  562.                         textLen := Length(controlHdl^^.contrlTitle);
  563.                         if textLen > 0 then
  564.                             err := PtrToHand(@controlHdl^^.contrlTitle[1], controlDataHdl^^.fTextHandle, textLen);
  565.  
  566.             { Insert the text representing the value, if requested; we need to call the routine ConvertValueToText each }
  567.             { time we draw, to respond properly to script system switches (for example, if the user switches from the }
  568.             { Roman script to the Japanese script) }
  569.                         if BAND(extVarCode, kDrawTitleAndValueVarCodeMask) <> 0 then
  570.                             ConvertValueToText(controlDataHdl, controlHdl^^.contrlRfCon, controlDataHdl^^.fTextHandle, textLen);
  571.                     end
  572.                 else if BAND(extVarCode, kDrawValueOnlyVarCodeMask) <> 0 then
  573.                     begin
  574.  
  575.             { Allocate a zero-sized handle to be filled later by ConvertValueToText }
  576.                         textLen := 0;
  577.                         controlDataHdl^^.fTextHandle := NewHandleClear(textLen);
  578.                         if MemError = noErr then
  579.                             ConvertValueToText(controlDataHdl, controlHdl^^.contrlRfCon, controlDataHdl^^.fTextHandle, textLen);
  580.                     end;
  581.             end;
  582.  
  583.     { Lock the text to avoid problems }
  584.         HLock(controlDataHdl^^.fTextHandle);
  585.  
  586.     { Call NeoTextBox to draw the text }
  587.         linesDrawn := NeoTextBox(controlDataHdl^^.fTextHandle^, textLen, controlBounds, controlDataHdl^^.fJustification, 0, endY, lhUsed, kDontSwapClipping);
  588.  
  589.     { Unlock the text }
  590.         HUnlock(controlDataHdl^^.fTextHandle);
  591.  
  592.     { Do not keep the text allocated across calls, but only if the kDrawTextFromRefCon variation is clear }
  593.         if BAND(extVarCode, kDrawTextFromRefConVarCodeMask) = 0 then
  594.             begin
  595.                 DisposeHandle(controlDataHdl^^.fTextHandle);
  596.                 controlDataHdl^^.fTextHandle := nil;
  597.             end;
  598.  
  599.     { Dim the text with the 'old' method }
  600.         if dimFlag & (not controlDataHdl^^.fHasGrayishTextOr) then
  601.             begin
  602.                 PenPat(controlDataHdl^^.fDitherPattern);
  603.                 PenMode(srcBic);
  604.                 PaintRect(controlBounds);
  605.             end;
  606.     end;
  607.  
  608.  
  609. {    BlitGaussControl    }
  610. {}
  611. {    DeviceLoop draw routine to copy the control drawing from the offscreen world to the control's port    }
  612. {}
  613. {    Entry:    inDepth = depth of current device    }
  614. {            inDeviceFlags = flags describing current device properties (unused)    }
  615. {            inTargetDevice = handle to current device (unused)    }
  616. {            inUserData = container for the control's handle }
  617.     procedure BlitGaussControl (inDepth: UInt16;
  618.                                     inDeviceFlags: SInt16;
  619.                                     inTargetDevice: GDHandle;
  620.                                     inUserData: SInt32);
  621.         var
  622.             controlBounds: Rect;
  623.             controlDataHdl: GaussCDEFDataHandle;
  624.             offWorldPtr: GWorldPtr;
  625.             controlPort: CGrafPtr;
  626.     begin
  627.  
  628.     { Get the control's data, the control's port and the control's rect }
  629.         controlDataHdl := GaussCDEFDataHandle(ControlHandle(inUserData)^^.contrlData);
  630.         controlPort := CGrafPtr(ControlHandle(inUserData)^^.contrlOwner);
  631.         controlBounds := ControlHandle(inUserData)^^.contrlRect;
  632.  
  633.     { Proceed only if the offscreen world is available }
  634.         if controlDataHdl^^.fOffscreenDrawAvailable then
  635.             begin
  636.                 offWorldPtr := controlDataHdl^^.fOffscreenWorldPtr;
  637.  
  638.         { The offscreen world's pixMap has already been locked by the caller, so we set the port }
  639.         { to the control's owner, set the foreground color to black and background color to white to avoid colorization }
  640.         { by CopyBits and start blitting }
  641.                 SetGWorld(controlPort, nil);
  642.                 RGBForeColor(controlDataHdl^^.fBlackColor);
  643.                 RGBBackColor(controlDataHdl^^.fWhiteColor);
  644.                 CopyBits(GrafPtr(offWorldPtr)^.portBits, GrafPtr(controlPort)^.portBits, offWorldPtr^.portRect, controlBounds, srcCopy, nil);
  645.             end;
  646.     end;
  647.  
  648.  
  649. {    BeginDraw    }
  650. {}
  651. {    Responds to the drawCntl message by saving the current port, color, ecc. settings, by activating ours and    }
  652. {    by calling DeviceLoop to draw the control    }
  653. {}
  654. {    Entry:    inControlHdl = handle to current control    }
  655.     procedure BeginDraw (inControlHdl: ControlHandle);
  656.         var
  657.             saveForeColor, saveBackColor: RGBColor;
  658.             savePen: PenState;
  659.             saveClip, controlRgn: RgnHandle;
  660.             auxWinHdl: AuxWinHandle;
  661.             savePort, controlPort: CGrafPtr;
  662.             saveDevice: GDHandle;
  663.             controlDataHdl: GaussCDEFDataHandle;
  664.             extVarCode: SInt16;
  665.             err: OSErr;
  666.     begin
  667.  
  668.     { Exit immediately if our custom data isn't available }
  669.         controlDataHdl := GaussCDEFDataHandle(inControlHdl^^.contrlData);
  670.         if controlDataHdl = nil then
  671.             Exit(BeginDraw);
  672.  
  673.     { Save current settings (port, clipping, colors, ecc.) }
  674.         GetGWorld(savePort, saveDevice);
  675.         controlPort := CGrafPtr(inControlHdl^^.contrlOwner);
  676.         SetGWorld(controlPort, nil);
  677.         GetForeColor(saveForeColor);
  678.         GetBackColor(saveBackColor);
  679.         GetPenState(savePen);
  680.  
  681.     { Now the current port is the control's port, and we intersect its clipping region with our control rectangle; if this }
  682.     { intersection is empty then exit without drawing anything. This indeed means that all our drawing would be clipped out }
  683.         controlRgn := NewRgn;
  684.         saveClip := NewRgn;
  685.  
  686.         if (saveClip <> nil) and (controlRgn <> nil) then
  687.             begin
  688.                 GetClip(saveClip);
  689.                 RectRgn(controlRgn, inControlHdl^^.contrlRect);
  690.  
  691.         { Intersect the current clip region with the control's rectangle: if this intersection is empty then dispose of our }
  692.         { regions and exit }
  693.                 SectRgn(saveClip, controlRgn, controlRgn);
  694.                 if EmptyRgn(controlRgn) then
  695.                     begin
  696.                         DisposeRgn(saveClip);
  697.                         DisposeRgn(controlRgn);
  698.                         SetGWorld(savePort, saveDevice);
  699.                         Exit(BeginDraw);
  700.                     end
  701.                 else
  702.  
  703.         { All right: set the clip region to the previously calculated intersection and go ahead }
  704.                     SetClip(controlRgn);
  705.             end
  706.         else
  707.  
  708.     { Bad, bad: we don't have enough memory to allocate 2 regions, so exit }
  709.             begin
  710.                 SetGWorld(savePort, saveDevice);
  711.                 Exit(BeginDraw);
  712.             end;
  713.  
  714.     { Lock our data to avoid problems }
  715.         HLock(Handle(controlDataHdl));
  716.  
  717.     { Get a copy of our extended variation code }
  718.         extVarCode := controlDataHdl^^.fVariationCode;
  719.  
  720.     { Read the justification from the contrlValue field }
  721.         controlDataHdl^^.fJustification := inControlHdl^^.contrlValue;
  722.  
  723.     { Save the text settings of the control's owner (they're always used by the DrawGaussControl routine }
  724.         controlDataHdl^^.fSaveTxFont := controlPort^.txFont;
  725.         controlDataHdl^^.fSaveTxSize := controlPort^.txSize;
  726.         controlDataHdl^^.fSaveTxFace := controlPort^.txFace;
  727.         controlDataHdl^^.fSaveTxMode := controlPort^.txMode;
  728.  
  729.     { Dimming with the 'cctb' colors requires informations about the foreground color of the control's window, so }
  730.     { store it into our data to avoid another couple of Get/SetGWorld calls later }
  731.         if BAND(extVarCode, kUseStdColorsExtVarCodeMask) = 0 then
  732.             if (BAND(extVarCode, kNeverDimControlExtVarCodeMask) = 0) & (inControlHdl^^.contrlHilite = kControlInactivePart) then
  733.                 controlDataHdl^^.fControlOwnerForeColor := saveForeColor;
  734.  
  735.     { Store into our data the content color of the control's window, because we will need it to frame the }
  736.     { control's bounds when not drawing the inset border; we try to not use the saved back color because it isn't reliable }
  737.         if GetAuxWin(WindowPtr(controlPort), auxWinHdl) then
  738.             ;
  739.         if (auxWinHdl <> nil) & (auxWinHdl^^.awCTable <> nil) then
  740.             begin
  741.                 HLock(Handle(auxWinHdl^^.awCTable));
  742.                 controlDataHdl^^.fControlOwnerContentColor := auxWinHdl^^.awCTable^^.ctTable[wContentColor].rgb;
  743.                 HUnlock(Handle(auxWinHdl^^.awCTable));
  744.             end
  745.         else
  746.             controlDataHdl^^.fControlOwnerContentColor := saveBackColor;
  747.  
  748.     { Create the offscreen drawing world }
  749.         err := CreateControlOffscreenWorld(inControlHdl, controlDataHdl^^.fOffscreenWorldPtr);
  750.  
  751.     { Examine the offscreen world to see if it has been created successfully }
  752.         if (err = noErr) and (controlDataHdl^^.fOffscreenWorldPtr <> nil) then
  753.             controlDataHdl^^.fOffscreenDrawAvailable := LockPixels(GetGWorldPixMap(controlDataHdl^^.fOffscreenWorldPtr));
  754.  
  755.     { Call DeviceLoop to draw the control either in the offscreen world (then blitting it to the control's port) or directly }
  756.     { into the control's port }
  757.         if controlDataHdl^^.fOffscreenDrawAvailable then
  758.             begin
  759.  
  760.         { Draw the control in the offscreen world }
  761.                 DeviceLoop(controlPort^.visRgn, controlDataHdl^^.fDrawControlUPP, SInt32(inControlHdl), kDeviceLoopFlags);
  762.  
  763.         { Copy the newly drawn control from the offscreen world to the control's port }
  764.                 DeviceLoop(controlPort^.visRgn, controlDataHdl^^.fBlitControlUPP, SInt32(inControlHdl), kDeviceLoopFlags);
  765.                 UnlockPixels(GetGWorldPixMap(controlDataHdl^^.fOffscreenWorldPtr));
  766.  
  767.                 DisposeGWorld(controlDataHdl^^.fOffscreenWorldPtr);
  768.                 controlDataHdl^^.fOffscreenWorldPtr := nil;
  769.                 controlDataHdl^^.fOffscreenDrawAvailable := false;
  770.             end
  771.         else
  772.  
  773.         { The offscreen world is not accessible, so we draw in the control's port anyway }
  774.             DeviceLoop(controlPort^.visRgn, controlDataHdl^^.fDrawControlUPP, SInt32(inControlHdl), kDeviceLoopFlags);
  775.  
  776.     { Restore the previously saved settings, unlock our data and exit }
  777.         TextFont(controlDataHdl^^.fSaveTxFont);
  778.         TextSize(controlDataHdl^^.fSaveTxSize);
  779.         TextFace(controlDataHdl^^.fSaveTxFace);
  780.         TextMode(controlDataHdl^^.fSaveTxMode);
  781.         SetClip(saveClip);
  782.         if saveClip <> nil then
  783.             DisposeRgn(saveClip);
  784.         if controlRgn <> nil then
  785.             DisposeRgn(controlRgn);
  786.         RGBForeColor(saveForeColor);
  787.         RGBBackColor(saveBackColor);
  788.         SetPenState(savePen);
  789.         SetGWorld(savePort, saveDevice);
  790.         HUnlock(Handle(controlDataHdl));
  791.     end;
  792.  
  793.  
  794. {    InitControlData    }
  795. {}
  796. {    Allocates and initializes the control's private data    }
  797. {    Note that if the kDrawTextFromRefCon variation is set we don't allocate any memory for the text. We    }
  798. {    consider this text's storage to be the responsibility of the calling application, to allow for flexibility (so    }
  799. {    that the calling application isn't forced to display only one text for the entire lifespan of this control) and to allow    }
  800. {    the application check the memory allocation for the text (IM-Macintosh Toolbox Essentials specifies that a CDEF should    }
  801. {    always respond with 0 to the initCntl message, so there's no means to report a failed allocation to the calling application).    }
  802. {}
  803. {    Entry:    inControlHdl = handle to current control    }
  804. {            inVarCode = variation code of current control    }
  805.     procedure InitControlData (inControlHdl: ControlHandle;
  806.                                     inVarCode: SInt16);
  807.         var
  808.             theDataHdl: GaussCDEFDataHandle;
  809.             drawUPP, blitUPP: DeviceLoopDrawingUPP;
  810.             response: SInt32;
  811.             err: OSErr;
  812.             titleLength: SInt16;
  813.     begin
  814.         theDataHdl := nil;
  815.  
  816.     { Allocate memory for the control's data }
  817.         theDataHdl := GaussCDEFDataHandle(NewHandleClear(SizeOf(GaussCDEFData)));
  818.         err := MemError;
  819.  
  820.     { If the allocation was successful then fill in the fields, else punt }
  821.         if (err = noErr) and (theDataHdl <> nil) then
  822.             begin
  823.  
  824.         { Lock the data to avoid problems (the following calls are supposed to move memory) }
  825.                 HLock(Handle(theDataHdl));
  826.  
  827.         { Store the draw and blit procedures }
  828.                 drawUPP := NewDeviceLoopDrawingProc(@DrawGaussControl);
  829.                 theDataHdl^^.fDrawControlUPP := drawUPP;
  830.                 blitUPP := NewDeviceLoopDrawingProc(@BlitGaussControl);
  831.                 theDataHdl^^.fBlitControlUPP := blitUPP;
  832.  
  833.         { The initial text justification is the contrlValue field }
  834.                 theDataHdl^^.fJustification := inControlHdl^^.contrlValue;
  835.  
  836.         { Retrieve the extended variation codes from the contrlMax field and add them to the 'real' variation codes }
  837.                 inVarCode := BOR(BAND(inControlHdl^^.contrlMax, kHighOrderByteMask), inVarCode);
  838.  
  839.         { Eliminate here the combinations of variation codes that are not allowed }
  840.         { kDrawTextFromRefCon, kDrawTitleAndValue, kDrawValueOnly cannot appear together; we must choose only one, with }
  841.         { the following priorities: 1) kDrawValueOnly 2) kDrawTitleAndValue 3) kDrawTextFromRefCon }
  842.         { kDraw3DEffect requires kDrawBoundingRectangle, so if the latter is clear we clear the former also }
  843.                 if BAND(inVarCode, kDrawValueOnlyVarCodeMask) <> 0 then
  844.                     if BAND(inVarCode, kDrawTitleAndValueVarCodeMask + kDrawTextFromRefConVarCodeMask) <> 0 then
  845.                         inVarCode := BAND(inVarCode, BNOT(kDrawTitleAndValueVarCodeMask + kDrawTextFromRefConVarCodeMask));
  846.                 if BAND(inVarCode, kDrawTitleAndValueVarCodeMask) <> 0 then
  847.                     if BAND(inVarCode, kDrawTextFromRefConVarCodeMask) <> 0 then
  848.                         inVarCode := BAND(inVarCode, BNOT(kDrawTextFromRefConVarCodeMask));
  849.                 if BAND(inVarCode, kDraw3DEffectExtVarCodeMask) <> 0 then
  850.                     if BAND(inVarCode, kDrawBoundingRectangleExtVarCodeMask) = 0 then
  851.                         inVarCode := BAND(inVarCode, BNOT(kDraw3DEffectExtVarCodeMask));
  852.  
  853.         { Store the massaged variation codes into the data structure }
  854.                 theDataHdl^^.fVariationCode := inVarCode;
  855.  
  856.         { Allocate the memory for the two number parts tables used to convert numbers to text. I'd like to check }
  857.         { for storage allocation errors, but a CDEF can only return 0 from the initCntl message }
  858.                 if (BAND(inVarCode, (kDrawTitleAndValueVarCodeMask + kDrawValueOnlyVarCodeMask)) <> 0) then
  859.                     begin
  860.                         theDataHdl^^.fReferenceNumPartsPtr := NumberPartsPtr(NewPtrClear(SizeOf(NumberParts)));
  861.                         theDataHdl^^.fUserNumPartsPtr := NumberPartsPtr(NewPtrClear(SizeOf(NumberParts)));
  862.                     end;
  863.  
  864.         { Store the patterns; getting them via Resource Mgr. calls helps insulating us from using the evil }
  865.         { QuickDraw globals }
  866.                 GetIndPattern(theDataHdl^^.fBlackPattern, sysPatListID, kBlackPatternIndex);
  867.                 GetIndPattern(theDataHdl^^.fWhitePattern, sysPatListID, kWhitePatternIndex);
  868.                 GetIndPattern(theDataHdl^^.fDitherPattern, sysPatListID, kGrayPatternIndex);
  869.  
  870.         { Store the colors; note that the foreground and background colors of the control's window are stored }
  871.         { by the BeginDraw procedure }
  872.                 SetRGBColor(theDataHdl^^.fBlackColor, kBlackColorRGBComp, kBlackColorRGBComp, kBlackColorRGBComp);
  873.                 SetRGBColor(theDataHdl^^.fWhiteColor, kWhiteColorRGBComp, kWhiteColorRGBComp, kWhiteColorRGBComp);
  874.                 SetRGBColor(theDataHdl^^.fDimGrayColor, kDimGrayColorRGBComp, kDimGrayColorRGBComp, kDimGrayColorRGBComp);
  875.  
  876.         { This color is calculated only if the variation code specifies that we should draw the 3D effect }
  877.                 if BAND(inVarCode, kDraw3DEffectExtVarCodeMask) <> 0 then
  878.                     SetRGBColor(theDataHdl^^.fChiselGrayColor, kChiselGrayColorRGBComp, kChiselGrayColorRGBComp, kChiselGrayColorRGBComp);
  879.  
  880.         { Check if we can use the grayishTextOr transfer mode }
  881.                 err := Gestalt(gestaltQuickDrawFeatures, response);
  882.                 theDataHdl^^.fHasGrayishTextOr := (err = noErr) & BTST(response, gestaltHasGrayishTextOr);
  883.  
  884.         { Unlock data }
  885.                 HUnlock(Handle(theDataHdl));
  886.             end;
  887.  
  888.     { Store the initialized data in the contrlData field; note that even the NIL handle of an unsuccessful }
  889.     { allocation is stored, because is checked by the draw routine that exits if encounters such a handle }
  890.         inControlHdl^^.contrlData := Handle(theDataHdl);
  891.     end;
  892.  
  893.  
  894. {    DisposeControlData    }
  895. {}
  896. {    Disposes of all the private data created at initialization time    }
  897. {}
  898. {    Entry:    inControlHdl = handle to control    }
  899.     procedure DisposeControlData (inControlHdl: ControlHandle);
  900.         var
  901.             theDataHdl: GaussCDEFDataHandle;
  902.     begin
  903.         theDataHdl := GaussCDEFDataHandle(inControlHdl^^.contrlData);
  904.  
  905.     { Go ahead only if our data is not NIL }
  906.         if theDataHdl <> nil then
  907.             begin
  908.  
  909.         { Dispose of the draw and blit UPPs }
  910.                 DisposeRoutineDescriptor(theDataHdl^^.fDrawControlUPP);
  911.                 DisposeRoutineDescriptor(theDataHdl^^.fBlitControlUPP);
  912.  
  913.         { Dispose of the title text if we allocated it, i.e. if the calling application specified a variation code }
  914.         { other than kDrawTextFromRefCon }
  915.                 if BAND(theDataHdl^^.fVariationCode, kDrawTextFromRefConVarCodeMask) = 0 then
  916.                     if theDataHdl^^.fTextHandle <> nil then
  917.                         DisposeHandle(theDataHdl^^.fTextHandle);
  918.  
  919.         { Dispose of our GWorld }
  920.                 if theDataHdl^^.fOffscreenWorldPtr <> nil then
  921.                     DisposeGWorld(theDataHdl^^.fOffscreenWorldPtr);
  922.  
  923.         { Dispose of our NumberParts tables }
  924.                 if theDataHdl^^.fReferenceNumPartsPtr <> nil then
  925.                     DisposePtr(Ptr(theDataHdl^^.fReferenceNumPartsPtr));
  926.                 if theDataHdl^^.fUserNumPartsPtr <> nil then
  927.                     DisposePtr(Ptr(theDataHdl^^.fUserNumPartsPtr));
  928.  
  929.         { Finally, dispose of the data itself and set it to NIL to avoid multiple disposal }
  930.                 DisposeHandle(Handle(theDataHdl));
  931.                 theDataHdl := nil;
  932.             end;
  933.     end;
  934.  
  935.  
  936. {    GaussCDEF    }
  937. {}
  938. {    Main entry point for the control definition function. Dispatches the messages to the    }
  939. {    appropriate subroutines    }
  940. {}
  941. {    Entry:    inVarCode = variation of control to handle    }
  942. {            inControlHdl =    handle to ControlRecord describing the current control    }
  943. {            inMessage = identifies the subfunction requested    }
  944. {            inParam = variable value, depending on inMessage    }
  945. {    Exit:    function result = variable value, depending on inMessage    }
  946.     function GaussCDEF (inVarCode: SInt16;
  947.                                     inControlHdl: ControlHandle;
  948.                                     inMessage: ControlDefProcMessage;
  949.                                     inParam: SInt32): SInt32;
  950.         var
  951.             returnValue: SInt32;
  952.             ctrlRecState: SignedByte;
  953.     begin
  954.  
  955.     { Don't waste time if we're called with a NIL control handle (this should not happen anyway) }
  956.         if inControlHdl = nil then
  957.             Exit(GaussCDEF);
  958.  
  959.     { Lock down our control for the whole drawing time }
  960.         ctrlRecState := HGetState(Handle(inControlHdl));
  961.         HLock(Handle(inControlHdl));
  962.  
  963.     { Return 0 as default from our defproc (we don't have indicators) }
  964.         returnValue := 0;
  965.  
  966.     { Dispatch the current message to the appropriate subroutine }
  967.         case inMessage of
  968.  
  969.         { Draw the control (only if it's visible) }
  970.             drawCntl: 
  971.                 if inControlHdl^^.contrlVis <> 0 then
  972.                     BeginDraw(inControlHdl);
  973.  
  974.         { Initializes the control's data }
  975.             initCntl: 
  976.                 InitControlData(inControlHdl, inVarCode);
  977.  
  978.         { Disposes of the control's data }
  979.             dispCntl: 
  980.                 DisposeControlData(inControlHdl);
  981.  
  982.         { Return kInGaussControlPart if the click is inside the control's rect }
  983.             testCntl: 
  984.                 if PtInRect(Point(inParam), inControlHdl^^.contrlRect) then
  985.                     returnValue := kInGaussControlPart;
  986.  
  987.         { Return the control's rectangle as a region, in 32-bit addressing mode }
  988.             calcCntlRgn: 
  989.                 RectRgn(RgnHandle(inParam), inControlHdl^^.contrlRect);
  990.  
  991.         { Return the control's rectangle as a region, in 24-bit addressing mode; note that IM-Toolbox Essentials }
  992.         { p. 5-112 says that we should clear the high-order bit before calculating the region, but does not specify }
  993.         { that the region handle we return must be confined to the low 3 bytes of inParam }
  994.             calcCRgns: 
  995.                 if BAND(inParam, kClearHighByteMask) = 0 then
  996.                     RectRgn(RgnHandle(StripAddress(inParam)), inControlHdl^^.contrlRect);
  997.  
  998.             otherwise
  999.                 ;
  1000.         end;
  1001.  
  1002.     { Unlock the control and return }
  1003.         HSetState(Handle(inControlHdl), ctrlRecState);
  1004.         GaussCDEF := returnValue;
  1005.     end;
  1006.  
  1007.  
  1008. end.